<template>
  <a-drawer
    :visible="formVisible"
    :width="500"
    unmount-on-close
    :title="isEdit ? '编辑' : '新增'"
    @ok="submit"
    @cancel="handleCancel"
  >
    <div>
      <a-form
        ref="formRef"
        :model="form"
        :rules="rules"
        :label-col-props="{ span: 8 }"
        :wrapper-col-props="{ span: 16 }"
      >
        <a-form-item field="parentId" label="上级菜单">
          <a-tree-select
            v-model="form.parentId"
            :data="treeData"
            placeholder="请选择上级菜单"
          />
        </a-form-item>
        <a-form-item field="type" label="菜单类型">
          <a-select v-model="form.type" :options="MENU_TYPES"></a-select>
        </a-form-item>
        <a-form-item field="title" label="菜单名称">
          <a-input v-model="form.title" placeholder="请填写菜单名称" />
        </a-form-item>
        <a-form-item field="permission" label="权限标识">
          <a-input v-model="form.permission" placeholder="请填写权限标识" />
        </a-form-item>
        <a-form-item label="排序" field="sort">
          <a-input-number v-model="form.sort" />
        </a-form-item>
        <a-form-item v-if="form.type === MenuType.MENU" label="图标">
          <a-space align="center">
            <a-button @click="iconVisible = true">选择图标</a-button>
            <component
              :is="iconOf(form.icon)"
              v-if="form.icon && iconOf(form.icon)"
              class="icon-show"
              :size="24"
            />
          </a-space>
        </a-form-item>
        <a-form-item
          v-if="form.type === MenuType.MENU"
          field="name"
          label="路由名称"
          :rules="menuRules('路由名称')"
        >
          <a-input v-model="form.name" placeholder="请填写路由名称" />
        </a-form-item>
        <a-form-item
          v-if="form.type === MenuType.MENU"
          field="path"
          label="菜单编码"
          :rules="menuRules('菜单编码')"
        >
          <a-input v-model="form.path" placeholder="请填写菜单编码" />
        </a-form-item>
        <a-form-item
          v-if="form.type === MenuType.MENU"
          field="component"
          label="菜单路径"
          :rules="menuRules('菜单路径')"
        >
          <a-input v-model="form.component" placeholder="请填写菜单路径" />
        </a-form-item>
        <a-form-item
          v-if="!isEdit"
          label="赋权角色"
          field="roleId"
          :rules="editRules('赋权角色')"
        >
          <a-select
            v-model="form.roleId"
            placeholder="请选择赋权角色"
            allow-clear
            :options="roles"
            :field-names="{
              value: 'id',
              label: 'roleName',
            }"
          />
        </a-form-item>
      </a-form>
    </div>
  </a-drawer>
  <IconChoose
    v-model:visible="iconVisible"
    @choose="(v:any) => (form.icon = v)"
  />
</template>

<script lang="ts" setup>
  import { FieldRule, Message } from '@arco-design/web-vue';
  import { ref, watch, computed } from 'vue';
  import {
    addMenu,
    updateMenu,
    MENU_TYPES,
    getMenuList,
    MenuType,
  } from '@/api/upms/menu';
  import { getRoleList } from '@/api/upms/role';
  import { camelCase } from 'lodash';
  import { useRequest } from 'vue-request';
  import { assembleTree } from '@/utils/util';
  import IconChoose from './icon-choose.vue';

  const props = defineProps({
    visible: {
      type: Boolean,
      default: false,
    },
    refreshList: {
      type: Boolean,
      default: false,
    },
    formData: {
      type: Object,
      default: () => {
        return {};
      },
    },
  });

  const { data: roles } = useRequest(getRoleList);

  const formRef = ref();

  // 初始数据
  const initData = () => {
    return {
      id: '',
      name: '',
      title: '',
      permission: '',
      parentId: '',
      icon: '',
      component: '',
      sort: '',
      path: '',
      keepAlive: '',
      roleId: '',
    };
  };

  /**
   * 菜单数据
   */
  const form = ref(props.formData);

  /**
   * 图标库选择
   */
  const iconVisible = ref(false);

  const iconOf = (name?: string) => name && camelCase(name);

  const rules: Record<string, FieldRule[]> = {
    title: [
      {
        type: 'string',
        required: true,
        message: '菜单名不能为空',
      },
    ],
    type: [
      {
        type: 'string',
        required: true,
        message: '菜单类型不能为空',
      },
    ],
    parentId: [
      {
        type: 'string',
        required: true,
        message: '上级菜单不能为空',
      },
    ],
  };

  const emit = defineEmits<{
    (e: 'update:visible', v: boolean): void;
    (e: 'refresh'): void;
  }>();
  const formVisible = ref(false);

  const { data: menuData } = useRequest(
    async () => assembleTree(await getMenuList()),
    {
      // 显示的时候刷新
      ready: computed(() => props.visible),
    }
  );

  const treeData = computed(() => [
    { title: '顶级菜单', key: '0', children: menuData.value },
  ]);

  // 判断是编辑还是新增
  const isEdit = computed(() => !!form.value.id);

  const editRules = (label: string) => {
    return [
      {
        validator: (value: string, cb: any) =>
          !isEdit.value && !value && cb(`${label}不能为空`),
      },
    ];
  };

  const menuRules = (label: string) => {
    return [
      {
        validator: (value: string, cb: any) =>
          form.value.type === MenuType.MENU && !value && cb(`${label}不能为空`),
      },
    ];
  };

  const submit = async () => {
    formVisible.value = true;
    const validate = await formRef.value.validate();
    if (!validate) {
      if (isEdit.value) {
        await updateMenu(form.value).then(() => {
          Message.success('修改成功');
        });
      } else {
        await addMenu(form.value).then(() => {
          Message.success('添加成功');
        });
      }
      form.value = { ...initData };
      formVisible.value = false;
      emit('refresh');
    }
  };

  const handleCancel = () => {
    formVisible.value = false;
    form.value = { ...initData };
  };

  watch(
    () => formVisible.value,
    (val) => {
      emit('update:visible', val);
    }
  );

  watch(
    () => props.visible,
    (val) => {
      formVisible.value = val;
    }
  );

  watch(
    () => props.formData,
    (val) => {
      form.value = val;
    }
  );
</script>
